package com.example.service.impl;

import com.example.common.Result;
import com.example.dto.WorkScheduleDateDTO;
import com.example.entity.WorkSchedule;
import com.example.entity.WorkScheduleDate;
import com.example.mapper.WorkScheduleDateMapper;
import com.example.mapper.WorkScheduleMapper;
import com.example.service.WorkScheduleDateService;
import com.example.util.UserContextUtil;
import com.example.vo.WorkScheduleDateVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 日期排班服务实现类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class WorkScheduleDateServiceImpl implements WorkScheduleDateService {
    
    private final WorkScheduleDateMapper workScheduleDateMapper;
    private final WorkScheduleMapper workScheduleMapper;
    private final UserContextUtil userContextUtil;
    
    // 星期几名称映射
    private static final Map<Integer, String> DAY_OF_WEEK_NAMES = Map.of(
        1, "周一", 2, "周二", 3, "周三", 4, "周四", 
        5, "周五", 6, "周六", 7, "周日"
    );
    
    @Override
    @Transactional
    public Result<Void> addWorkScheduleDate(WorkScheduleDateDTO workScheduleDateDTO) {
        try {
            // 获取当前用户ID（店长ID）
            Long storeManagerId = userContextUtil.getCurrentUserId();
            if (storeManagerId == null) {
                return Result.error("用户未登录");
            }
            
            // 参数校验
            Result<Void> validationResult = validateWorkScheduleDateDTO(workScheduleDateDTO);
            if (!validationResult.isSuccess()) {
                return validationResult;
            }
            
            // 检查时间段是否冲突
            int conflictCount = workScheduleDateMapper.checkDateTimeConflict(
                storeManagerId, workScheduleDateDTO.getScheduleDate(),
                workScheduleDateDTO.getStartHour(), workScheduleDateDTO.getEndHour(), null
            );
            if (conflictCount > 0) {
                return Result.error("该时间段与现有排班冲突");
            }
            
            // 创建日期排班记录
            WorkScheduleDate workScheduleDate = new WorkScheduleDate();
            workScheduleDate.setStoreManagerId(storeManagerId);
            workScheduleDate.setScheduleDate(workScheduleDateDTO.getScheduleDate());
            workScheduleDate.setStartHour(workScheduleDateDTO.getStartHour());
            workScheduleDate.setEndHour(workScheduleDateDTO.getEndHour());
            workScheduleDate.setMaxAppointments(workScheduleDateDTO.getMaxAppointments());
            workScheduleDate.setStatus(workScheduleDateDTO.getStatus() != null ? workScheduleDateDTO.getStatus() : 1);
            workScheduleDate.setRemark(workScheduleDateDTO.getRemark());
            workScheduleDate.setCreateTime(LocalDateTime.now());
            workScheduleDate.setUpdateTime(LocalDateTime.now());
            workScheduleDate.setDeleted(0);
            
            int result = workScheduleDateMapper.insert(workScheduleDate);
            if (result > 0) {
                return Result.success();
            } else {
                return Result.error("添加日期排班失败");
            }
        } catch (Exception e) {
            log.error("添加日期排班失败", e);
            return Result.error("添加日期排班失败：" + e.getMessage());
        }
    }
    
    @Override
    @Transactional
    public Result<Void> updateWorkScheduleDate(Long id, WorkScheduleDateDTO workScheduleDateDTO) {
        try {
            // 获取当前用户ID（店长ID）
            Long storeManagerId = userContextUtil.getCurrentUserId();
            if (storeManagerId == null) {
                return Result.error("用户未登录");
            }
            
            // 检查排班是否存在
            WorkScheduleDate existingSchedule = workScheduleDateMapper.selectById(id);
            if (existingSchedule == null || existingSchedule.getDeleted() == 1) {
                return Result.error("日期排班记录不存在");
            }
            
            // 检查是否是当前店长的排班
            if (!existingSchedule.getStoreManagerId().equals(storeManagerId)) {
                return Result.error("无权限修改此排班");
            }
            
            // 参数校验
            Result<Void> validationResult = validateWorkScheduleDateDTO(workScheduleDateDTO);
            if (!validationResult.isSuccess()) {
                return validationResult;
            }
            
            // 检查时间段是否冲突（排除当前记录）
            int conflictCount = workScheduleDateMapper.checkDateTimeConflict(
                storeManagerId, workScheduleDateDTO.getScheduleDate(),
                workScheduleDateDTO.getStartHour(), workScheduleDateDTO.getEndHour(), id
            );
            if (conflictCount > 0) {
                return Result.error("该时间段与现有排班冲突");
            }
            
            // 更新日期排班记录
            WorkScheduleDate workScheduleDate = new WorkScheduleDate();
            workScheduleDate.setId(id);
            workScheduleDate.setScheduleDate(workScheduleDateDTO.getScheduleDate());
            workScheduleDate.setStartHour(workScheduleDateDTO.getStartHour());
            workScheduleDate.setEndHour(workScheduleDateDTO.getEndHour());
            workScheduleDate.setMaxAppointments(workScheduleDateDTO.getMaxAppointments());
            workScheduleDate.setStatus(workScheduleDateDTO.getStatus());
            workScheduleDate.setRemark(workScheduleDateDTO.getRemark());
            workScheduleDate.setUpdateTime(LocalDateTime.now());
            
            int result = workScheduleDateMapper.updateById(workScheduleDate);
            if (result > 0) {
                return Result.success();
            } else {
                return Result.error("更新日期排班失败");
            }
        } catch (Exception e) {
            log.error("更新日期排班失败", e);
            return Result.error("更新日期排班失败：" + e.getMessage());
        }
    }
    
    @Override
    @Transactional
    public Result<Void> deleteWorkScheduleDate(Long id) {
        try {
            // 获取当前用户ID（店长ID）
            Long storeManagerId = userContextUtil.getCurrentUserId();
            if (storeManagerId == null) {
                return Result.error("用户未登录");
            }
            
            // 检查排班是否存在
            WorkScheduleDate existingSchedule = workScheduleDateMapper.selectById(id);
            if (existingSchedule == null || existingSchedule.getDeleted() == 1) {
                return Result.error("日期排班记录不存在");
            }
            
            // 检查是否是当前店长的排班
            if (!existingSchedule.getStoreManagerId().equals(storeManagerId)) {
                return Result.error("无权限删除此排班");
            }
            
            int result = workScheduleDateMapper.deleteById(id);
            if (result > 0) {
                return Result.success();
            } else {
                return Result.error("删除日期排班失败");
            }
        } catch (Exception e) {
            log.error("删除日期排班失败", e);
            return Result.error("删除日期排班失败：" + e.getMessage());
        }
    }
    
    @Override
    public Result<WorkScheduleDateVO> getWorkScheduleDateById(Long id) {
        try {
            // 获取当前用户ID（店长ID）
            Long storeManagerId = userContextUtil.getCurrentUserId();
            if (storeManagerId == null) {
                return Result.error("用户未登录");
            }
            
            WorkScheduleDate workScheduleDate = workScheduleDateMapper.selectById(id);
            if (workScheduleDate == null || workScheduleDate.getDeleted() == 1) {
                return Result.error("日期排班记录不存在");
            }
            
            // 检查是否是当前店长的排班
            if (!workScheduleDate.getStoreManagerId().equals(storeManagerId)) {
                return Result.error("无权限查看此排班");
            }
            
            WorkScheduleDateVO vo = convertToVO(workScheduleDate);
            return Result.success(vo);
        } catch (Exception e) {
            log.error("查询日期排班详情失败", e);
            return Result.error("查询日期排班详情失败：" + e.getMessage());
        }
    }
    
    @Override
    public Result<List<WorkScheduleDateVO>> getMyWorkScheduleDates() {
        try {
            // 获取当前用户ID（店长ID）
            Long storeManagerId = userContextUtil.getCurrentUserId();
            if (storeManagerId == null) {
                return Result.error("用户未登录");
            }
            
            List<WorkScheduleDate> schedules = workScheduleDateMapper.selectByStoreManagerId(storeManagerId);
            List<WorkScheduleDateVO> vos = schedules.stream()
                .map(this::convertToVO)
                .sorted(Comparator.comparing(WorkScheduleDateVO::getScheduleDate)
                    .thenComparing(WorkScheduleDateVO::getStartHour))
                .collect(Collectors.toList());
            
            return Result.success(vos);
        } catch (Exception e) {
            log.error("查询日期排班列表失败", e);
            return Result.error("查询日期排班列表失败：" + e.getMessage());
        }
    }
    
    @Override
    public Result<List<WorkScheduleDateVO>> getMyWorkScheduleDatesByDate(LocalDate scheduleDate) {
        try {
            // 获取当前用户ID（店长ID）
            Long storeManagerId = userContextUtil.getCurrentUserId();
            if (storeManagerId == null) {
                return Result.error("用户未登录");
            }
            
            if (scheduleDate == null) {
                return Result.error("日期参数错误");
            }
            
            List<WorkScheduleDate> schedules = workScheduleDateMapper.selectByStoreManagerIdAndDate(storeManagerId, scheduleDate);
            List<WorkScheduleDateVO> vos = schedules.stream()
                .map(this::convertToVO)
                .sorted(Comparator.comparing(WorkScheduleDateVO::getStartHour))
                .collect(Collectors.toList());
            
            return Result.success(vos);
        } catch (Exception e) {
            log.error("查询指定日期排班列表失败", e);
            return Result.error("查询指定日期排班列表失败：" + e.getMessage());
        }
    }
    
    @Override
    public Result<List<WorkScheduleDateVO>> getMyWorkScheduleDatesByDateRange(LocalDate startDate, LocalDate endDate) {
        try {
            // 获取当前用户ID（店长ID）
            Long storeManagerId = userContextUtil.getCurrentUserId();
            if (storeManagerId == null) {
                return Result.error("用户未登录");
            }
            
            if (startDate == null || endDate == null) {
                return Result.error("日期参数错误");
            }
            
            if (startDate.isAfter(endDate)) {
                return Result.error("开始日期不能晚于结束日期");
            }
            
            List<WorkScheduleDate> schedules = workScheduleDateMapper.selectByStoreManagerIdAndDateRange(storeManagerId, startDate, endDate);
            List<WorkScheduleDateVO> vos = schedules.stream()
                .map(this::convertToVO)
                .sorted(Comparator.comparing(WorkScheduleDateVO::getScheduleDate)
                    .thenComparing(WorkScheduleDateVO::getStartHour))
                .collect(Collectors.toList());
            
            return Result.success(vos);
        } catch (Exception e) {
            log.error("查询日期范围排班列表失败", e);
            return Result.error("查询日期范围排班列表失败：" + e.getMessage());
        }
    }
    
    @Override
    @Transactional
    public Result<Void> batchSetWorkScheduleDates(List<WorkScheduleDateDTO> workScheduleDateDTOs) {
        try {
            // 获取当前用户ID（店长ID）
            Long storeManagerId = userContextUtil.getCurrentUserId();
            if (storeManagerId == null) {
                return Result.error("用户未登录");
            }
            
            if (workScheduleDateDTOs == null || workScheduleDateDTOs.isEmpty()) {
                return Result.error("排班数据不能为空");
            }
            
            // 逐个添加排班
            for (WorkScheduleDateDTO dto : workScheduleDateDTOs) {
                Result<Void> result = addWorkScheduleDate(dto);
                if (!result.isSuccess()) {
                    // 如果有失败的，记录日志但继续处理其他的
                    log.warn("批量设置日期排班时失败：{}", result.getMessage());
                }
            }
            
            return Result.success();
        } catch (Exception e) {
            log.error("批量设置日期排班失败", e);
            return Result.error("批量设置日期排班失败：" + e.getMessage());
        }
    }
    
    @Override
    @Transactional
    public Result<Void> clearScheduleByDate(LocalDate scheduleDate) {
        try {
            // 获取当前用户ID（店长ID）
            Long storeManagerId = userContextUtil.getCurrentUserId();
            if (storeManagerId == null) {
                return Result.error("用户未登录");
            }
            
            if (scheduleDate == null) {
                return Result.error("日期参数错误");
            }
            
            // 获取该日期的所有排班
            List<WorkScheduleDate> schedules = workScheduleDateMapper.selectByStoreManagerIdAndDate(storeManagerId, scheduleDate);
            
            // 逻辑删除所有排班
            for (WorkScheduleDate schedule : schedules) {
                workScheduleDateMapper.deleteById(schedule.getId());
            }
            
            return Result.success();
        } catch (Exception e) {
            log.error("清空日期排班失败", e);
            return Result.error("清空日期排班失败：" + e.getMessage());
        }
    }
    
    @Override
    public Result<List<Integer[]>> getOccupiedTimeSlotsForDate(LocalDate scheduleDate) {
        try {
            // 获取当前用户ID（店长ID）
            Long storeManagerId = userContextUtil.getCurrentUserId();
            if (storeManagerId == null) {
                return Result.error("用户未登录");
            }
            
            if (scheduleDate == null) {
                return Result.error("日期参数错误");
            }
            
            // 获取该日期的所有排班
            List<WorkScheduleDate> schedules = workScheduleDateMapper.selectByStoreManagerIdAndDate(storeManagerId, scheduleDate);
            
            // 转换为时间段数组
            List<Integer[]> occupiedSlots = schedules.stream()
                .map(schedule -> new Integer[]{schedule.getStartHour(), schedule.getEndHour()})
                .collect(Collectors.toList());
            
            return Result.success(occupiedSlots);
        } catch (Exception e) {
            log.error("获取已排班时间段失败", e);
            return Result.error("获取已排班时间段失败：" + e.getMessage());
        }
    }
    
    @Override
    @Transactional
    public Result<Void> copyFromWeeklyTemplate(LocalDate scheduleDate) {
        try {
            // 获取当前用户ID（店长ID）
            Long storeManagerId = userContextUtil.getCurrentUserId();
            if (storeManagerId == null) {
                return Result.error("用户未登录");
            }
            
            if (scheduleDate == null) {
                return Result.error("日期参数错误");
            }
            
            // 获取该日期对应的星期几
            DayOfWeek dayOfWeek = scheduleDate.getDayOfWeek();
            int dayOfWeekValue = dayOfWeek.getValue(); // 1=Monday, 7=Sunday
            
            // 获取周排班模板
            List<WorkSchedule> weeklySchedules = workScheduleMapper.selectByStoreManagerIdAndDayOfWeek(storeManagerId, dayOfWeekValue);
            
            if (weeklySchedules.isEmpty()) {
                return Result.error("该星期几没有设置排班模板");
            }
            
            // 检查该日期是否已有排班
            List<WorkScheduleDate> existingSchedules = workScheduleDateMapper.selectByStoreManagerIdAndDate(storeManagerId, scheduleDate);
            if (!existingSchedules.isEmpty()) {
                return Result.error("该日期已有排班，请先清空后再复制");
            }
            
            // 复制周排班到日期排班
            for (WorkSchedule weeklySchedule : weeklySchedules) {
                WorkScheduleDate dateSchedule = new WorkScheduleDate();
                dateSchedule.setStoreManagerId(storeManagerId);
                dateSchedule.setScheduleDate(scheduleDate);
                dateSchedule.setStartHour(weeklySchedule.getStartHour());
                dateSchedule.setEndHour(weeklySchedule.getEndHour());
                dateSchedule.setMaxAppointments(weeklySchedule.getMaxAppointments());
                dateSchedule.setStatus(weeklySchedule.getStatus());
                dateSchedule.setRemark(weeklySchedule.getRemark());
                dateSchedule.setCreateTime(LocalDateTime.now());
                dateSchedule.setUpdateTime(LocalDateTime.now());
                dateSchedule.setDeleted(0);
                
                workScheduleDateMapper.insert(dateSchedule);
            }
            
            return Result.success();
        } catch (Exception e) {
            log.error("从周排班模板复制失败", e);
            return Result.error("从周排班模板复制失败：" + e.getMessage());
        }
    }
    
    /**
     * 参数校验
     */
    private Result<Void> validateWorkScheduleDateDTO(WorkScheduleDateDTO dto) {
        if (dto.getScheduleDate() == null) {
            return Result.error("排班日期不能为空");
        }
        
        if (dto.getScheduleDate().isBefore(LocalDate.now())) {
            return Result.error("不能设置过去的日期排班");
        }
        
        if (dto.getStartHour() == null || dto.getStartHour() < 8 || dto.getStartHour() > 20) {
            return Result.error("开始时间参数错误，应为8-20");
        }
        
        if (dto.getEndHour() == null || dto.getEndHour() < 8 || dto.getEndHour() > 20) {
            return Result.error("结束时间参数错误，应为8-20");
        }
        
        if (dto.getStartHour() >= dto.getEndHour()) {
            return Result.error("开始时间必须小于结束时间");
        }
        
        if (dto.getMaxAppointments() == null || dto.getMaxAppointments() < 1 || dto.getMaxAppointments() > 50) {
            return Result.error("可预约人数参数错误，应为1-50");
        }
        
        return Result.success();
    }
    
    /**
     * 转换为VO
     */
    private WorkScheduleDateVO convertToVO(WorkScheduleDate workScheduleDate) {
        WorkScheduleDateVO vo = new WorkScheduleDateVO();
        vo.setId(workScheduleDate.getId());
        vo.setStoreManagerId(workScheduleDate.getStoreManagerId());
        vo.setScheduleDate(workScheduleDate.getScheduleDate());
        vo.setScheduleDateStr(workScheduleDate.getScheduleDate().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        
        // 设置星期几名称
        DayOfWeek dayOfWeek = workScheduleDate.getScheduleDate().getDayOfWeek();
        vo.setDayOfWeekName(DAY_OF_WEEK_NAMES.get(dayOfWeek.getValue()));
        
        vo.setStartHour(workScheduleDate.getStartHour());
        vo.setEndHour(workScheduleDate.getEndHour());
        vo.setTimeRange(workScheduleDate.getStartHour() + ":00-" + workScheduleDate.getEndHour() + ":00");
        vo.setMaxAppointments(workScheduleDate.getMaxAppointments());
        vo.setStatus(workScheduleDate.getStatus());
        vo.setStatusName(workScheduleDate.getStatus() == 1 ? "启用" : "禁用");
        vo.setRemark(workScheduleDate.getRemark());
        vo.setCreateTime(workScheduleDate.getCreateTime());
        vo.setUpdateTime(workScheduleDate.getUpdateTime());
        
        return vo;
    }
} 